package com.lingchou.cloud.process.client.cmd;

import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.cmd.AbstractDynamicInjectionCmd;
import org.flowable.engine.impl.dynamic.BaseDynamicSubProcessInjectUtil;
import org.flowable.engine.impl.persistence.entity.DeploymentEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class SummaryApprovalCmd extends AbstractDynamicInjectionCmd implements Command<Void> {
    private final String processInstanceId;
    private final UserTask currentTask;
    private final List<FlowElement> elements;

    public SummaryApprovalCmd(String processInstanceId, UserTask currentTask, List<FlowElement> elements) {
        this.processInstanceId = processInstanceId;
        this.currentTask = currentTask;
        this.elements = elements;
    }

    @Override
    public Void execute(CommandContext commandContext) {
        createDerivedProcessDefinitionForProcessInstance(commandContext, processInstanceId);
        return null;
    }

    @Override
    protected void updateBpmnProcess(CommandContext commandContext, Process process, BpmnModel bpmnModel, ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity) {
        //流程中的任务节点
        List<UserTask> userTasks = process.findFlowElementsOfType(UserTask.class);
        //结束节点
        List<String> endEventIds = process.findFlowElementsOfType(EndEvent.class).stream().map(EndEvent::getId).collect(Collectors.toList());
        //任务的id 与 实体映射 便于搜索
        Map<String, UserTask> userTaskMap = userTasks.stream().collect(Collectors.toMap(UserTask::getId, a -> a, (k1, k2) -> k1));
        //当前task
        UserTask userTask = userTasks.stream().filter(u -> currentTask.getId().equals(u.getId())).findFirst().orElseThrow(NullPointerException::new);
        //当前节点的唯一出口 以当前的方式 应该有一个
        SequenceFlow outgoingFlowForCur = userTask.getOutgoingFlows().get(0);
        //删除后续节点
        removeElement(outgoingFlowForCur,userTaskMap,endEventIds,process);
        //添加新元素
        elements.forEach(process::addFlowElement);
        BaseDynamicSubProcessInjectUtil.processFlowElements(commandContext, process, bpmnModel, originalProcessDefinitionEntity, newDeploymentEntity);
    }

    @Override
    protected void updateExecutions(CommandContext commandContext, ProcessDefinitionEntity processDefinitionEntity, ExecutionEntity processInstance, List<ExecutionEntity> childExecutions) {
    }

    /**
     * 递归删除后续节点
     *
     * @param sequenceFlow 当前连线
     * @param userTaskMap  全部任务
     * @param endEventIds  结束节点
     * @param process      流程
     */
    private void removeElement(SequenceFlow sequenceFlow, Map<String, UserTask> userTaskMap, List<String> endEventIds, Process process) {
        //删除当前线
        process.removeFlowElement(sequenceFlow.getId());
        //获取连线目标阶段
        String nextElementId = sequenceFlow.getTargetFlowElement().getId();
        //判断是否是结束节点 是则跳出
        if (endEventIds.contains(nextElementId)) {
            return;
        }
        //判断是否是任务阶段
        if (userTaskMap.containsKey(nextElementId)) {
            //获取任务 并 删除
            UserTask userTask = userTaskMap.get(nextElementId);
            process.removeFlowElement(userTask.getId());
            //获取边界事件 并 删除
            BoundaryEvent boundaryEvent = userTask.getBoundaryEvents().get(0);
            process.removeFlowElement(boundaryEvent.getId());
            //获取边界事件的后续连线 并 删除
            SequenceFlow beSequenceFlow = boundaryEvent.getOutgoingFlows().get(0);
            process.removeFlowElement(beSequenceFlow.getId());
            //递归删除后续
            SequenceFlow nextSeq = userTask.getOutgoingFlows().get(0);
            removeElement(nextSeq, userTaskMap, endEventIds, process);
        }
    }
}
